package auditoryUIbk;
import jass.generators.*;
import jass.engine.*;

/**
   A force model based on looping through a buffer once, loaded from an audio
   file or provided by caller.
   @author Kees van den Doel (kvdoel@cs.ubc.ca)
   Pierre Dragicevic
*/
public class StereoSample {
	
	  /** True if is outputting buffer. */
    private boolean isPlaying = false;

    /** Buffer to loop */
    protected float[] sample;

    /** Buffer length */
    protected int sampleLength;

    /** Loop speed through buffer in seconds per second. */
    protected float speed = 1;

    /** Current fposition of pointer in buffer. */
    protected float x = 0;

   /**  Current speed of pointer  in  buffer  per sample. */
    protected float dx;
    
    /** Sampling rate in Hertz of Out. */
    public float srate;

    /** Sampling rate ratio, sratesample/srate */
    private float srateRatio = 1;

    /** Sampling rate in Hertz of loaded buffer. */
    protected float sratesample;
    
    protected float volume = 1;
    protected float destvolume = 1, deltavolume = 0;
    protected String file;
    
    public StereoSample prototype = null;
    // log info
    SoundSet parent;
    int index_in_parent;
    int instance_counter;
    static int last_instance_counter = 0;
    static Logger logger = null;

    public StereoSample(SoundSet parent, int index_in_parent, float srate, String fn, float leftVolume, float rightVolume, float leftDelay, float rightDelay, float noiseLevelBefore, float noiseLevelAfter) {
        StereoFileBuffer afBuffer = StereoFileBuffer.getBuffer(fn, leftVolume, rightVolume, leftDelay, rightDelay, noiseLevelBefore, noiseLevelAfter);
        this.prototype = this;
        this.parent = parent;
        this.index_in_parent = index_in_parent;
        this.file = fn;
        sample = afBuffer.buf;
        sampleLength = 1000;//sample.length/4;
        sratesample = afBuffer.srate;
        this.srate = srate;
        srateRatio = sratesample/srate;
        setSpeed(speed);
        stop();
        instance_counter = last_instance_counter;
        last_instance_counter++;
        log("loaded");
    }
    
    public StereoSample(StereoSample sts) {
    	prototype = sts;
    	parent = sts.parent;
    	index_in_parent = sts.index_in_parent;
        sample = sts.sample;
        sampleLength = sts.sampleLength;
        dx = sts.dx;
        sratesample = sts.sratesample;
        volume = sts.volume;
        instance_counter = last_instance_counter;
        last_instance_counter++;
    }

    /** Get the sample as array.
        @return The containing sample
    */
    public float[] getsample() {
        return sample;
    }

    /** Set loopspeed.
        @param speed Loop speed., 1 corresponding to original recorded speed.
    */
    public void setSpeed(float speed) {
        this.speed = speed;
        dx = speed * srateRatio;
    }
    
    public void setVolume(float volume) {
    	this.volume = volume;
    }
    
    public float getVolume() {
    	if (deltavolume == 0) {
    		return volume;
    	} else {
    		return destvolume;
    	}
    }
    
    public void animateVolume(float vol, float time) {
    	this.destvolume = vol;
    	this.deltavolume = (destvolume-volume) / sratesample / time / 2f; // stereo
    }

    /** Get next sample value, interpolating in between sample points.
     */
    protected float getNextSample() {
        if (!isPlaying) return 0;

        // ---------- we need to implement a stereo method!
        
/*        x += dx;
        if (x >= sampleLength-1) {
            pause();
            return 0;
        }

{
        if (dx < 1) {
          int ix = (int)x;
          float fx = x-ix;
          return ((1 - fx) * sample[ix] + fx * sample[ix+1]) * volume;
        } else if (dx > 1) {
          return sample[(int)x] * volume;
        } else {
          return sample[(int)x] * volume;
        }*/
        
        // volume animation
        if (deltavolume != 0) {
        	volume += deltavolume;
        	if (deltavolume > 0 && volume > destvolume) {
        		volume = destvolume;
        		deltavolume = 0;
        	} else if (deltavolume < 0 && volume < destvolume) {
        		volume = destvolume;
        		deltavolume = 0;
        	}
        }

        // get next sample if exists
        x++;
        if (x == sampleLength) {
            pause();
            return 0;
        }
        float y = sample[(int)x] * volume;
        return y;
    }
    
    public float getDuration() {
    	return sampleLength / sratesample / 2f; // stereo
    }

    public void replay() {
			  reset();
			  play();
	  }
	  
	  public void stop() {
			  pause();
			  reset();
	  }
	
    public void play() {
    	if (!isPlaying) {
    		log("play");
    	}
        isPlaying = true;
    }
    
    public void pause() {
    	if (isPlaying) {
    		log("stop");
    	}
        isPlaying = false;
    }

    public void reset() {
        x = 0;
    }
    
    public int getSampleLength(){
    	return sample.length;
    }
    
    public void setLength(int len){
    	sampleLength = len;
    }
    
    public boolean playing() {
    	return isPlaying;
    }
    
    void log(String event){
    	if (logger == null) {
    		logger = Logger.createLogger("audio_log");
    	}
    	// Build args String
    	String args = "";
    	// 1 - the unique ID of the sound being played
    	args += this.instance_counter + Logger.msSeparator;
    	// 2 - the ID of the sound from which this transient instance has been cloned
    	args += prototype.instance_counter + Logger.msSeparator;
    	// 3 - the sound filename
    	args += prototype.file + Logger.msSeparator;
    	// 4 - the owner SoundSet's name
    	args += prototype.parent.name + Logger.msSeparator;
    	// 5 - the index of this sound in the SoundSet
    	args += prototype.index_in_parent + Logger.msSeparator;
    	// 6 - the total number of sounds in the SoundSet (or rather, the max index used + 1)
    	args += (prototype.parent.maxindex+1) + Logger.msSeparator;
    	// 7 - the current location of the play cursor in the sample (in milliseconds)
    	args += this.x * 1000.0 / prototype.sratesample / 2 + Logger.msSeparator;
    	// 8 - the total length of the sample (in milliseconds)
    	args += prototype.sampleLength * 1000.0 / prototype.sratesample / 2 + Logger.msSeparator;
    	// 9 - the current sample volume (between 0 and 1)
    	args += this.volume * prototype.parent.volume + Logger.msSeparator;
    	logger.log(event, args);
    }
}



